package com.cristina.attention.consumer;

import com.cristina.attention.utils.GroupIdMappingUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.kafka.annotation.KafkaListenerAnnotationBeanPostProcessor;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 启动消费者
 *
 * @author by superman
 */
@Service
public class ReceiverServer {

    @Resource
    private ApplicationContext context;

    /**
     * Receiver 消费方法常量
     */
    private static final String RECEIVER_METHOD_NAME = "Receiver.consumer";

    /**
     * 获取对应类型的 groupId
     */
    private static List<String> groupIds = GroupIdMappingUtils.getAllGroupIds();

    /**
     * 迭代 groupIds 位置的下表
     */
    private static Integer index = 0;

    /**
     * 为每一个渠道不同的消息类型创建一个 Receiver 对象
     */
    @PostConstruct
    public void init() {
        for (int i = 0; i < groupIds.size(); i++) {
            context.getBean(Receiver.class);
        }
    }

    /**
     * 给每个 Receiver 对象的 chatAsyncDatabase/pushNotify 方法 @KafkaListener groupId 赋值
     * <p>
     * KafkaListenerAnnotationBeanPostProcessor.AnnotationEnhancer / 官方描述: 后处理每组注解属性(Post processes each set of annotation attributes).
     * 具体用法暂未明确
     * </p>
     *
     * @return
     */
    @Bean
    public static KafkaListenerAnnotationBeanPostProcessor.AnnotationEnhancer groupIdEnhancer() {
        return (attrs, element) -> {
            if (element instanceof Method) {
                String name = ((Method) element).getDeclaringClass().getSimpleName() + "." + ((Method) element).getName();
                if (Objects.equals(RECEIVER_METHOD_NAME, name)) {
                    attrs.put("groupId", groupIds.get(index));
                    index++;
                }
            }
            return attrs;
        };
    }

}
